/**
 * @作者 zw
 * @微信公号 搬砖暗夜码农
 * @开源项目 $ https://gitee.com/zhouwei5208888/spring-boot-distributed
 * @我的博客 $ http://itzhouwei.com
 * @创建时间 2025/1/20 14:07
 */
package com.itzhouwei.commerce.redis.aspect;

import com.itzhouwei.commerce.redis.annotation.RepeatRestrict;
import com.itzhouwei.commerce.redis.utlis.RedisOperator;
import io.jsonwebtoken.Claims;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * @ClassName：RepeatRestrictAspect 防重复提交切面
 * @Version：1.0
 * @Author: zw，微信公共号：搬砖暗夜码农
 * @Date: 2025/1/20 14:07
 * @Description:
 * @Copyright：公众号：搬砖暗夜码农 | 博客：https://itzhouwei.com - 沉淀、学习、分享、成长，让自己和他人都能有所收获！
 */
@Aspect
@Component
@Slf4j
public class RepeatRestrictAspect {

    @Autowired
    private RedisOperator redisTemplate;


    @Around("@annotation(com.itzhouwei.commerce.redis.annotation.RepeatRestrict)")
    public Object around(ProceedingJoinPoint point) throws Throwable {

        Method method = ((MethodSignature) point.getSignature()).getMethod();
        RepeatRestrict annotation = method.getAnnotation(RepeatRestrict.class);

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String subKeyOne;
        if (StringUtils.isNotBlank(annotation.key())) {
            subKeyOne = annotation.key();
        } else {
            subKeyOne = request.getRequestURI();
        }

        String subKeyTwo;
        if (annotation.checkUser()) {
            //todo 需要自己去补充完整
            subKeyTwo = getUserIdIsNotError() + "";
        } else {
            subKeyTwo = getIpAddr(request);
        }

        if (StringUtils.isBlank(subKeyTwo)) {
            return point.proceed();
        }

        String redisKey = buildKey("repeatSubmitTicket", subKeyOne, subKeyTwo);
        Object redisValue = redisTemplate.get(redisKey);
        int number = 1;
        if (redisValue != null) {
            number = (int) redisValue;
            if (number >= annotation.number()) {
                throw new RuntimeException("提交频繁");
            }
            ++number;
        }
        try {
            redisTemplate.set(redisKey, number + "", annotation.time());
        } catch (Throwable throwable) {
            log.error("high error 接口限流存储redis错误-> ", throwable);
        }
        return point.proceed();

    }


    /**
     * 获得当前请求的用户Id,不返回错误
     *
     * @return
     */
    public static Long getUserIdIsNotError() {
/*
        todo
        获取当前的用户id
        String token = getToken();
        if (StringUtils.isEmpty(token)) {
            return -1L;
        }
        try {
            Claims claims = jwtTokenKit.getTokenBody(token);
            return Long.parseLong(claims.get("id").toString());
        }catch (Exception e){
            return -1L;
        }*/
        return -1L;
    }



    /***
     * 拿到对应的ip
     * @param request
     * @return
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ipAddress;
        try {
            ipAddress = request.getHeader("x-forwarded-for");
            // 对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
            // "***.***.***.***".length()
            if (ipAddress != null && ipAddress.length() > 15) {
                if (ipAddress.indexOf(",") > 0) {
                    ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
                }
            }
        } catch (Exception e) {
            ipAddress = "";
        }
        return ipAddress;
    }

    /***
     * 构建key 以为什么开头
     * @param key
     * @return
     */
    private String buildKey(String... key) {
        StringBuilder sbKey = new StringBuilder();
        sbKey.append("zwmall");
        Arrays.stream(key).forEach(x -> {
            sbKey.append("::" + x);
        });
        return sbKey.toString();
    }

}
